#include "input.hpp"

#include "libutil.hpp"

const static bool DEBUG = false;

InputPort::InputPort () : pd (NULL), errmsg ("")
{
}

InputPort::~InputPort ()
{
  if (this->pd)
    pcap_close (this->pd);
}

bool InputPort::openFile (string fileName)
{
  char ebuf [PCAP_ERRBUF_SIZE];
  if (NULL == (this->pd = pcap_open_offline (fileName.c_str (), ebuf)))
    {
      this->setErrMsg ("Can't open pcapfile '" + fileName + "': " + ebuf);
      return false;
    }

  return true;
}

bool InputPort::openInterface (string devName)
{
  char ebuf [PCAP_ERRBUF_SIZE];
  if (NULL == (this->pd = pcap_open_live (devName.c_str (), 0xffff, 1, 10, ebuf)))
    {
      this->setErrMsg ("Can't open interface '" + devName + "': " + ebuf);
      return false;
    }

  /*
  if (NULL == (this->pd = pcap_create (devName.c_str (), ebuf)))
    {
      return false;
    }

  pcap_activate (this->pd);
  */

  return true;
}

bool InputPort::portReady ()
{
  if (this->pd)
    return true;
  else
    return false;
}


bool InputPort::setFilter (string filter)
{
  struct bpf_program fp;
  if (0 > pcap_compile(this->pd, &fp, filter.c_str (), 0, 0))
    {
      return false;
    }

  if (pcap_setfilter(this->pd, &fp) == -1) 
    {
      return false;
    }

  return true;
}

bool InputPort::getPacket (Packet * pkt) //Packet * pkt)
{
  struct pcap_pkthdr *h;
  const u_char * p;
  int ret ;

  if (! this->pd)
    return false;

  while (0 == (ret = pcap_next_ex (this->pd, &h, &p)))
    ;

  // if (ret == -1)
  if (ret != 1)
    {
      return false;
    }

  pkt->setData ((byte_t*)p, h->len, h->caplen, &h->ts);

  debug (DEBUG, "len = %d", h->len);
  return true;
}

InputPort::LinkType InputPort::getLinkType ()
{
  if (! this->pd)
    return LT_NULL;

  switch (pcap_datalink (this->pd))
    {
    case DLT_EN10MB: return LT_ETHERNET;
    case DLT_RAW:    return LT_RAWIP;
    default:
      return LT_NULL;
    }
}
